#include "SockError.h"
#include "../thread/SharedPtr.h"
#include "../tools/ShareApi.h"
#include "../stream/StringTools.h"

USE_LIBTOOLS;

CSockError::CSockError() :_ErrType(SUCC), _SysCode(0)
{

}

CSockError::CSockError(ErrorType type): _ErrType(SUCC), _SysCode(0)
{
	SetError(type);
}

CSockError::CSockError(DWORD code) :_ErrType(SUCC), _SysCode(0)
{
	SetSysError(code);
}

CSockError::CSockError(const CSockError& ec)
{
	if (this != &ec)
	{
		 _SysCode = ec._SysCode;
		 _ErrType = ec._ErrType;
	}
}

CSockError& CSockError::operator= (const CSockError& ec)
{
	if (this != &ec)
	{
		 _SysCode = ec._SysCode;
		 _ErrType = ec._ErrType;
	}
	return *this;
}

void CSockError::SetError(ErrorType type)
{
	 _ErrType = type;
	if(_ErrType == SYS_ERROR)
	{
#ifdef WIN32
		 _SysCode = WSAGetLastError();
#elif defined(LINUX)
		 _SysCode = errno;
#endif
	}
}

void CSockError::SetSysError(DWORD code)
{
	if (code == 0) {
		_ErrType = SUCC;
	}else {
		_ErrType = SYS_ERROR;
	}
	_SysCode = code;
}

bool CSockError::operator! () const
{
	return (_ErrType == SUCC);
}

CSockError::operator bool () const
{
	return _ErrType == SUCC ? false : true;
}

CSockError::ErrorType CSockError::GetError() const
{
	return _ErrType;
}

DWORD CSockError::GetSysError() const
{
	return _SysCode;
}

std::string CSockError::GetErrorMsg() const
{
	switch(_ErrType)
	{
	case SYS_ERROR:
		{
			SharedPtr<TCHAR> ptrErr(ShareApi::Global_GetLastError((DWORD*)&_SysCode), &ShareApi::Global_FreeMem);
			if (ptrErr.Get()){
				return STD_MOVE(TO_STRING(ptrErr.Get()));
			} else{
				return STD_MOVE(std::string("Unknown"));
			}
		}
		break;
	case DISCONNECT:
		{
			return STD_MOVE(std::string("Not connected or disconnect"));
		}
		break;
	case TIMEOUT:
		{
			return STD_MOVE(std::string("Time out"));
		}
		break;
	case UNINIT:
		{
			return STD_MOVE(std::string("Not Init"));
		}
		break;
	case BIND_SERVER_ERROR:
		{
			return STD_MOVE(std::string(("Bind server error")));
		}
	case SUCC:
		{
			return STD_MOVE(std::string("Succ"));
		}
		break;
	case CANCELIO:
		{
			return STD_MOVE(std::string("Operator cancel"));
		}
		break;
	case NOLISTEN:
		{
			return STD_MOVE(std::string("No listen"));
		}
		break;
	case NOFUNCTION:
		{
			return STD_MOVE(std::string("No function"));
		}
		break;
	default:
		{
			return STD_MOVE(std::string("Unknown"));
		}
		break;
	}

	return STD_MOVE(std::string(""));
}